package io.focus.mijin.zuul.ratelimit.support;

import io.focus.mijin.zuul.ratelimit.config.properties.RateLimitProperties;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.X_FORWARDED_FOR_HEADER;
import static io.focus.mijin.zuul.ratelimit.support.RateLimitConstants.*;

/**
 * @author Liel Chayoun
 */
@RequiredArgsConstructor
public final class RateLimitUtils {

    private static final String ANONYMOUS_USER = "anonymous";

    private final RateLimitProperties properties;

    public String getUser(HttpServletRequest request) {
        return request.getRemoteUser() != null ? request.getRemoteUser() : ANONYMOUS_USER;
    }

    /**
     * 获取Ip地址
     *
     * @param request
     * @return 真实
     */
    public String getRemoteIpAddress(HttpServletRequest request) {
        String xForIP = request.getHeader(X_FORWARDED_FOR_HEADER);
        if (StringUtils.isNotEmpty(xForIP) && !UN_KNOWN.equalsIgnoreCase(xForIP)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = xForIP.indexOf(",");
            return index != -1 ? xForIP.substring(0, index) : xForIP;
        }

        xForIP = getXForIpForHeader(X_REAL_IP, "", request);
        xForIP = getXForIpForHeader(PROXY_CLIENT_IP, xForIP, request);
        xForIP = getXForIpForHeader(WL_PROXY_CLIENT_IP, xForIP, request);
        xForIP = getXForIpForHeader(HTTP_CLIENT_IP, xForIP, request);
        xForIP = getXForIpForHeader(HTTP_X_FORWARDED_FOR, xForIP, request);
        if (StringUtils.isBlank(xForIP) || UN_KNOWN.equalsIgnoreCase(xForIP)) {
            xForIP = request.getRemoteAddr();
        }
        return properties.isBehindProxy() && StringUtils.isNotBlank(xForIP) ? xForIP : request.getRemoteAddr();
    }

    private String getXForIpForHeader(String header, String xForIP, HttpServletRequest request) {
        return StringUtils.isBlank(xForIP) || UN_KNOWN.equalsIgnoreCase(xForIP) ? request.getHeader(header) : header;
    }
}
